#include "Directory.h"

#include "File.h"
#include <Windows.h>
#include <queue>

using namespace std;

wstring Directory::mg_appendix = L"\\*";

Directory::Directory(const wstring& i_name)
  : m_dir_name(i_name)
  {
  m_dir_size = 0;
  DWORD dir_attributes = GetFileAttributes((WCHAR*)m_dir_name.c_str());

  if (dir_attributes & FILE_ATTRIBUTE_DIRECTORY)
    m_is_valid = true;
  else
    m_is_valid = false;
  }

Directory::Directory(const Directory&& i_ref)
  {
  m_dir_size = move(i_ref.m_dir_size);
  m_dir_name = move(i_ref.m_dir_name);
  m_is_valid = move(i_ref.m_is_valid);
  }

Directory::~Directory()
  {

  }

vector<wstring> Directory::GetChildren(EDirectoryChildren i_type) const
  {
  if (!m_is_valid) return vector<wstring>();
  
  // result file list
  vector<wstring> file_list;  

  // current file data
  WIN32_FIND_DATA fd;

  // search pattern
  TCHAR str_search[MAX_PATH];
  
  // std::string containing search pattern
  wstring temp_name = m_dir_name;
  temp_name.append(Directory::mg_appendix);

  // setting str_search string
    {
    int i = 0;
    while (temp_name[i])
      {
      str_search[i] = temp_name[i];
      ++i;
      }
    str_search[i] = '\0';
    }
 
  HANDLE h_item = FindFirstFile(str_search, &fd);
  wchar_t temp_fname[MAX_PATH];
  if (h_item != INVALID_HANDLE_VALUE)
    {
    do
      {
      // check input parameter and skip if current item doesnt match
      switch (i_type)
        {
        case EDirectoryChildren::DC_ALL:
          break;
        case EDirectoryChildren::DC_FILES:
          if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            continue;
          break;
        case EDirectoryChildren::DC_DIRECTORIES:
          if ( !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
            continue;
          break;
        default:
          break;
        }      
      
      // copying found file name to temp_fname  
      int i = 0;
      while (fd.cFileName[i] != 0)
        {
        temp_fname[i] = fd.cFileName[i];
        ++i;
        }
      temp_fname[i] = '\0';
      
      // converting temp_fname to std::string
      wstring fname(temp_fname);
      if (i_type == EDirectoryChildren::DC_DIRECTORIES)
        if (fname == L"." || fname == L"..")
          continue;
      file_list.push_back(fname);
      } while(FindNextFile(h_item, &fd) != 0);
    }
  FindClose(h_item);
  return file_list;
  }

wstring Directory::GetName() const
  {
  return m_dir_name;
  }

bool Directory::IsValid() const
  {
  return m_is_valid;
  }

unsigned __int64 Directory::GetSize()
  {
  if (m_dir_size != 0)
    return m_dir_size;

  for (auto& fname : GetChildren(EDirectoryChildren::DC_FILES))
    {
    File f(m_dir_name+L"\\"+fname);
    if (f.IsValid())
      m_dir_size += f.GetSize();
    }
  
  static queue<Directory> scan_queue;
  for (auto& dname : GetChildren(EDirectoryChildren::DC_DIRECTORIES))
    {
    scan_queue.push(Directory(m_dir_name + L"\\" + dname));
    }
  while (scan_queue.empty() == false)
    {
    Directory d = scan_queue.front();
    scan_queue.pop();
    m_dir_size += d.GetSize();
    }
  
  return m_dir_size;
  }